package com.jinyang.plugin002

import android.content.Context
import android.content.res.AssetManager
import android.content.res.Resources
import dalvik.system.DexClassLoader
import dalvik.system.PathClassLoader
import java.lang.Exception
import java.lang.reflect.Array

object LoadUtils {

    fun loadDex(context: Context, pluginPaths: List<String>) {
        try {
            // 获取 pathList
            val systemClassLoader = Class.forName("dalvik.system.BaseDexClassLoader")
            val pathListField = systemClassLoader.getDeclaredField("pathList")
            pathListField.isAccessible = true
            // 获取 dexElements
            val dexPathListClass = Class.forName("dalvik.system.DexPathList")
            val dexElementsField = dexPathListClass.getDeclaredField("dexElements")
            dexElementsField.isAccessible = true
            // 获取宿主的Elements
            val hostClassLoader = context.classLoader
            val hostPathList = pathListField.get(hostClassLoader)
            val hostElements = dexElementsField.get(hostPathList) as kotlin.Array<*>
            var newElements: kotlin.Array<*> = hostElements
            // 遍历获取插件的Elements
            for (path in pluginPaths) {
                val pluginClassLoader = PathClassLoader(path, context.classLoader)
                val pluginPathList = pathListField.get(pluginClassLoader)
                val pluginElements = dexElementsField.get(pluginPathList) as kotlin.Array<*>
                // 创建数组
                val temp = Array.newInstance(
                    pluginElements.javaClass.componentType!!,
                    newElements.size + pluginElements.size
                ) as kotlin.Array<*>

                // 给新数组赋值,先用宿主的，再用插件的
                System.arraycopy(newElements, 0, temp, 0, newElements.size)
                System.arraycopy(
                    pluginElements,
                    0,
                    temp,
                    newElements.size,
                    pluginElements.size
                )
                // 合并
                dexElementsField.set(hostPathList, temp)
                newElements = temp
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    fun loadResources(
        context: Context,
        assetManager: AssetManager,
        pluginPaths: List<String>
    ): Resources? {
        try {
            // 执行addAssetPath方法，添加资源加载路径
            val addAssetPathMethod =
                assetManager::class.java.getDeclaredMethod("addAssetPath", String::class.java)
            addAssetPathMethod.isAccessible = true
            for (path in pluginPaths) {
                addAssetPathMethod.invoke(assetManager, path)
            }
            // 创建Resources
            return Resources(
                assetManager,
                context.resources.displayMetrics,
                context.resources.configuration
            )
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return null
    }

}